public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Refactoring of timevar API
@ 2015-01-01  0:00 David Malcolm
  2015-01-01  0:00 ` [PATCH 1/2] gcc parts of timer refactoring David Malcolm
  2015-01-01  0:00 ` [PATCH 2/2] jit: add timing API David Malcolm
  0 siblings, 2 replies; 4+ messages in thread
From: David Malcolm @ 2015-01-01  0:00 UTC (permalink / raw)
  To: jit, gcc-patches; +Cc: David Malcolm

The attached two patches correspond to the first patch:
 "[PATCH 01/16] gcc: Generalization of timevar API; add gcc_jit_timer interface"
   https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00122.html
of the 16-patch kit I posted in June:
  https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00116.html

For ease of review, I've broken it up into two patches:

  * the first patch contains the changes to the core gcc directory
    (requires review)

  * the second patch contains the changes to the gcc/jit
    subdirectory (which I can self-approve).

That said, both patches require each other and would be
committed as one.

These patches are useful without needing the 15 followup patches,
in that they allow jit client code to control timing, leading to
more meaningful benchmark results).

For further motivation, see:
  https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00122.html

(as well as the split into a pair of patches, there are some
small changes to the jit side relative to that earlier patch).

Successfully bootstrapped & regrtested the combination of the two
patches on x86_64-pc-linux-gnu (Fedora 20) with all languages
other than ada [1].

jit.sum goes from 8494 to 8514 passes.

Are the non-jit parts OK for trunk?

[1] I ran into:
 a-chlat1.ads:16:08: warning: unrecognized pragma "Compiler_Unit_Warning"
on ada, which is apparently unrelated.

David Malcolm (2):
  gcc parts of timer refactoring
  jit: add timing API

 gcc/jit/docs/topics/compatibility.rst              |  21 ++
 gcc/jit/docs/topics/contexts.rst                   |   3 +-
 gcc/jit/docs/topics/index.rst                      |   1 +
 gcc/jit/docs/topics/performance.rst                | 240 ++++++++++++++++++++
 gcc/jit/jit-playback.c                             |  11 +-
 gcc/jit/jit-playback.h                             |   2 +
 gcc/jit/jit-recording.c                            |   2 +
 gcc/jit/jit-recording.h                            |   7 +
 gcc/jit/libgccjit++.h                              | 117 ++++++++++
 gcc/jit/libgccjit.c                                | 109 +++++++++
 gcc/jit/libgccjit.h                                |  84 +++++++
 gcc/jit/libgccjit.map                              |  12 +
 gcc/main.c                                         |   2 +-
 gcc/testsuite/jit.dg/test-benchmark.c              |  20 +-
 .../jit.dg/test-error-gcc_jit_timer_pop-mismatch.c |  22 ++
 .../jit.dg/test-error-gcc_jit_timer_pop-too-many.c |  21 ++
 gcc/timevar.c                                      | 247 ++++++++++++++++++---
 gcc/timevar.def                                    |   2 +
 gcc/timevar.h                                      |  35 ++-
 gcc/toplev.c                                       |  18 +-
 gcc/toplev.h                                       |   4 +-
 21 files changed, 926 insertions(+), 54 deletions(-)
 create mode 100644 gcc/jit/docs/topics/performance.rst
 create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-mismatch.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-too-many.c

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] gcc parts of timer refactoring
  2015-01-01  0:00 [PATCH 0/2] Refactoring of timevar API David Malcolm
@ 2015-01-01  0:00 ` David Malcolm
  2015-01-01  0:00   ` Jeff Law
  2015-01-01  0:00 ` [PATCH 2/2] jit: add timing API David Malcolm
  1 sibling, 1 reply; 4+ messages in thread
From: David Malcolm @ 2015-01-01  0:00 UTC (permalink / raw)
  To: jit, gcc-patches; +Cc: David Malcolm

In r223092 (aka dd4d567f4b6b498242097c41d63666bdae320ac1) I moved the
state of timevar.c from being global data into a "class timer" with
a global instance "g_timer".

This followup patch generalizes the timing within toplev so that an
external "timer" instance can (optionally) be passed in; this is used
in patch 2 to add an API to libgccjit for client code: gcc_jit_timer.

The gcc_jit_timer API allows client code to create arbitrary new timing
items (beyond the hardcoded list in timevar.def), giving them names,
so that client code can time whatever things are relevant to it; this
patch adds the support necessary to timevar.[ch] for this.

The patch also generalizes timevar.h's auto_timevar to avoid it
depending on the "g_timer" global (which is only set during the
lifetime of "toplev".  We can use this to add TV_JIT_ACQUIRING_MUTEX,
and thus measure wallclock time spent waiting for the JIT mutex.

Generalize timevar.c to add support for timing jit client code, by:

 * adding support for timing client items with arbitrary
   client-supplied names (e.g. "compiling code", "running code" etc).

 * supporting having a "timer" instance created externally and passed
   in to toplev, allowing clients to control where toplev's timing
   information is accumulated

 * add a couple of jit-specific timevars

This goes with the next patch; I've split them up for ease of review.

OK for trunk?

gcc/ChangeLog:
	* main.c (main): Pass in NULL for toplev's external_timer.
	* timevar.c: Include coretypes.h, hash-map.h, vec.h.
	(class timer::named_items): New.
	(timer::named_items::named_items): New.
	(timer::named_items::~named_items): New.
	(timer::named_items::push): New.
	(timer::named_items::pop): New.
	(timer::named_items::print): New.
	(timer::timer): Initialize field "m_jit_client_items".
	(timer::~timer): New.
	(timer::push): Move bulk of implementation to...
	(timer::push_internal): ...here.  New function.
	(timer::pop): Move bulk of implementation to...
	(timer::pop_internal): ...here.  New function.
	(timer::push_client_item): New.
	(timer::pop_client_item): New.
	(timer::print_row): New function, taken from timer::print.
	(timer::print): Print "GCC items" header if we also have client
	items.  Move row-printing to timer::print_row.  Print any client
	items.
	(timer::get_topmost_item_name): New method.
	* timevar.def (TV_JIT_ACQUIRING_MUTEX): New.
	(TV_JIT_CLIENT_CODE): New.
	* timevar.h (timer::push_client_item): New declaration.
	(timer::pop_client_item): New declaration.
	(timer::get_topmost_item_name): New method.
	(timer::push_internal): New declaration.
	(timer::pop_internal): New declaration.
	(timer::print_row): New declaration.
	(timer::named_items): New declaration.
	(timer::m_jit_client_items): New field.
	(timer): Add friend class named_items.
	(auto_timevar::auto_timevar): Add timer param.
	(auto_timevar::~auto_timevar): Use field "m_timer".
	(auto_timevar::m_timer): New field.
	* toplev.c (initialize_rtl): Add g_timer as param when
	constructing auto_timevar instance.
	(toplev::toplev): Add "external_timer" param, and use it to
	initialize the "g_timer" global if non-NULL.
	(toplev::~toplev): If this created "g_timer", delete it.
	* toplev.h (toplev::toplev): Replace "use_TV_TOTAL" bool param
	with "external_timer" timer *.
---
 gcc/main.c      |   2 +-
 gcc/timevar.c   | 247 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 gcc/timevar.def |   2 +
 gcc/timevar.h   |  35 +++++++-
 gcc/toplev.c    |  18 +++--
 gcc/toplev.h    |   4 +-
 6 files changed, 261 insertions(+), 47 deletions(-)

diff --git a/gcc/main.c b/gcc/main.c
index 79baf0d..bbd8b67 100644
--- a/gcc/main.c
+++ b/gcc/main.c
@@ -33,7 +33,7 @@ int main (int argc, char **argv);
 int
 main (int argc, char **argv)
 {
-  toplev toplev (true, /* use_TV_TOTAL */
+  toplev toplev (NULL, /* external_timer */
 		 true /* init_signals */);
 
   return toplev.main (argc, argv);
diff --git a/gcc/timevar.c b/gcc/timevar.c
index 76ad22a..eebb1dc 100644
--- a/gcc/timevar.c
+++ b/gcc/timevar.c
@@ -20,7 +20,10 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
 #include "timevar.h"
+#include "hash-map.h"
+#include "vec.h"
 
 #ifndef HAVE_CLOCK_T
 typedef int clock_t;
@@ -120,6 +123,93 @@ static void timevar_accumulate (struct timevar_time_def *,
 				struct timevar_time_def *,
 				struct timevar_time_def *);
 
+/* The implementation of timing events for jit client code, allowing
+   arbitrary named items to appear on the timing stack.  */
+
+class timer::named_items
+{
+ public:
+  named_items (timer *t);
+  ~named_items ();
+
+  void push (const char *item_name);
+  void pop ();
+  void print (FILE *fp, const timevar_time_def *total);
+
+ private:
+  /* Which timer instance does this relate to?  */
+  timer *m_timer;
+
+  /* Dictionary, mapping from item names to timevar_def.
+     Note that currently we merely store/compare the raw string
+     pointers provided by client code; we don't take a copy,
+     or use strcmp.  */
+  hash_map <const char *, timer::timevar_def> m_hash_map;
+
+  /* The order in which items were originally inserted.  */
+  auto_vec <const char *> m_names;
+};
+
+/* The constructor for class timer::named_items.  */
+
+timer::named_items::named_items (timer *t)
+: m_timer (t),
+  m_hash_map (),
+  m_names ()
+{
+}
+
+/* The destructor for class timer::named_items.  */
+
+timer::named_items::~named_items ()
+{
+}
+
+/* Push the named item onto the timer stack.  */
+
+void
+timer::named_items::push (const char *item_name)
+{
+  gcc_assert (item_name);
+
+  bool existed;
+  timer::timevar_def *def = &m_hash_map.get_or_insert (item_name, &existed);
+  if (!existed)
+    {
+      def->elapsed.user = 0;
+      def->elapsed.sys = 0;
+      def->elapsed.wall = 0;
+      def->name = item_name;
+      def->standalone = 0;
+      m_names.safe_push (item_name);
+    }
+  m_timer->push_internal (def);
+}
+
+/* Pop the top item from the timer stack.  */
+
+void
+timer::named_items::pop ()
+{
+  m_timer->pop_internal ();
+}
+
+/* Print the given client item.  Helper function for timer::print.  */
+
+void
+timer::named_items::print (FILE *fp, const timevar_time_def *total)
+{
+  unsigned int i;
+  const char *item_name;
+  fprintf (fp, "Client items:\n");
+  FOR_EACH_VEC_ELT (m_names, i, item_name)
+    {
+      timer::timevar_def *def = m_hash_map.get (item_name);
+      gcc_assert (def);
+      m_timer->print_row (fp, total, def);
+    }
+}
+
 /* Fill the current times into TIME.  The definition of this function
    also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and
    HAVE_WALL_TIME macros.  */
@@ -169,7 +259,8 @@ timevar_accumulate (struct timevar_time_def *timer,
 timer::timer () :
   m_stack (NULL),
   m_unused_stack_instances (NULL),
-  m_start_time ()
+  m_start_time (),
+  m_jit_client_items (NULL)
 {
   /* Zero all elapsed times.  */
   memset (m_timevars, 0, sizeof (m_timevars));
@@ -190,6 +281,26 @@ timer::timer () :
 #endif
 }
 
+/* Class timer's destructor.  */
+
+timer::~timer ()
+{
+  timevar_stack_def *iter, *next;
+
+  for (iter = m_stack; iter; iter=next)
+    {
+      next = iter->next;
+      free (iter);
+    }
+  for (iter = m_unused_stack_instances; iter; iter=next)
+    {
+      next = iter->next;
+      free (iter);
+    }
+
+  delete m_jit_client_items;
+}
+
 /* Initialize timing variables.  */
 
 void
@@ -212,9 +323,20 @@ void
 timer::push (timevar_id_t timevar)
 {
   struct timevar_def *tv = &m_timevars[timevar];
+  push_internal (tv);
+}
+
+/* Push TV onto the timing stack, either one of the builtin ones
+   for a timevar_id_t, or one provided by client code to libgccjit.  */
+
+void
+timer::push_internal (struct timevar_def *tv)
+{
   struct timevar_stack_def *context;
   struct timevar_time_def now;
 
+  gcc_assert (tv);
+
   /* Mark this timing variable as used.  */
   tv->used = 1;
 
@@ -258,11 +380,20 @@ timer::push (timevar_id_t timevar)
 void
 timer::pop (timevar_id_t timevar)
 {
+  gcc_assert (&m_timevars[timevar] == m_stack->timevar);
+
+  pop_internal ();
+}
+
+/* Pop the topmost item from the stack, either one of the builtin ones
+   for a timevar_id_t, or one provided by client code to libgccjit.  */
+
+void
+timer::pop_internal ()
+{
   struct timevar_time_def now;
   struct timevar_stack_def *popped = m_stack;
 
-  gcc_assert (&m_timevars[timevar] == m_stack->timevar);
-
   /* What time is it?  */
   get_time (&now);
 
@@ -410,6 +541,28 @@ timer::cond_stop (timevar_id_t timevar)
   timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
 }
 
+/* Push the named item onto the timing stack.  */
+
+void
+timer::push_client_item (const char *item_name)
+{
+  gcc_assert (item_name);
+
+  /* Lazily create the named_items instance.  */
+  if (!m_jit_client_items)
+    m_jit_client_items = new named_items (this);
+
+  m_jit_client_items->push (item_name);
+}
+
+/* Pop the top-most client item from the timing stack.  */
+
+void
+timer::pop_client_item ()
+{
+  gcc_assert (m_jit_client_items);
+  m_jit_client_items->pop ();
+}
 
 /* Validate that phase times are consistent.  */
 
@@ -462,6 +615,46 @@ timer::validate_phases (FILE *fp) const
     }
 }
 
+/* Helper function for timer::print.  */
+
+void
+timer::print_row (FILE *fp,
+		  const timevar_time_def *total,
+		  const timevar_def *tv)
+{
+  /* The timing variable name.  */
+  fprintf (fp, " %-24s:", tv->name);
+
+#ifdef HAVE_USER_TIME
+  /* Print user-mode time for this process.  */
+  fprintf (fp, "%7.2f (%2.0f%%) usr",
+	   tv->elapsed.user,
+	   (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
+#endif /* HAVE_USER_TIME */
+
+#ifdef HAVE_SYS_TIME
+  /* Print system-mode time for this process.  */
+  fprintf (fp, "%7.2f (%2.0f%%) sys",
+	   tv->elapsed.sys,
+	   (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
+#endif /* HAVE_SYS_TIME */
+
+#ifdef HAVE_WALL_TIME
+  /* Print wall clock time elapsed.  */
+  fprintf (fp, "%7.2f (%2.0f%%) wall",
+	   tv->elapsed.wall,
+	   (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
+#endif /* HAVE_WALL_TIME */
+
+  /* Print the amount of ggc memory allocated.  */
+  fprintf (fp, "%8u kB (%2.0f%%) ggc",
+	   (unsigned) (tv->elapsed.ggc_mem >> 10),
+	   (total->ggc_mem == 0
+	    ? 0
+	    : (float) tv->elapsed.ggc_mem / total->ggc_mem) * 100);
+
+  putc ('\n', fp);
+}
 
 /* Summarize timing variables to FP.  The timing variable TV_TOTAL has
    a special meaning -- it's considered to be the total elapsed time,
@@ -494,6 +687,8 @@ timer::print (FILE *fp)
   m_start_time = now;
 
   fputs ("\nExecution times (seconds)\n", fp);
+  if (m_jit_client_items)
+    fputs ("GCC items:\n", fp);
   for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
     {
       const timevar_def *tv = &m_timevars[(timevar_id_t) id];
@@ -516,39 +711,10 @@ timer::print (FILE *fp)
 	  && tv->elapsed.ggc_mem < GGC_MEM_BOUND)
 	continue;
 
-      /* The timing variable name.  */
-      fprintf (fp, " %-24s:", tv->name);
-
-#ifdef HAVE_USER_TIME
-      /* Print user-mode time for this process.  */
-      fprintf (fp, "%7.2f (%2.0f%%) usr",
-	       tv->elapsed.user,
-	       (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
-#endif /* HAVE_USER_TIME */
-
-#ifdef HAVE_SYS_TIME
-      /* Print system-mode time for this process.  */
-      fprintf (fp, "%7.2f (%2.0f%%) sys",
-	       tv->elapsed.sys,
-	       (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
-#endif /* HAVE_SYS_TIME */
-
-#ifdef HAVE_WALL_TIME
-      /* Print wall clock time elapsed.  */
-      fprintf (fp, "%7.2f (%2.0f%%) wall",
-	       tv->elapsed.wall,
-	       (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
-#endif /* HAVE_WALL_TIME */
-
-      /* Print the amount of ggc memory allocated.  */
-      fprintf (fp, "%8u kB (%2.0f%%) ggc",
-	       (unsigned) (tv->elapsed.ggc_mem >> 10),
-	       (total->ggc_mem == 0
-		? 0
-		: (float) tv->elapsed.ggc_mem / total->ggc_mem) * 100);
-
-      putc ('\n', fp);
+      print_row (fp, total, tv);
     }
+  if (m_jit_client_items)
+    m_jit_client_items->print (fp, total);
 
   /* Print total time.  */
   fputs (" TOTAL                 :", fp);
@@ -578,6 +744,17 @@ timer::print (FILE *fp)
   validate_phases (fp);
 }
 
+/* Get the name of the topmost item.  For use by jit for validating
+   inputs to gcc_jit_timer_pop.  */
+const char *
+timer::get_topmost_item_name () const
+{
+  if (m_stack)
+    return m_stack->timevar->name;
+  else
+    return NULL;
+}
+
 /* Prints a message to stderr stating that time elapsed in STR is
    TOTAL (given in microseconds).  */
 
diff --git a/gcc/timevar.def b/gcc/timevar.def
index aee36e6..ac41075 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -296,3 +296,5 @@ DEFTIMEVAR (TV_JIT_REPLAY	     , "replay of JIT client activity")
 DEFTIMEVAR (TV_ASSEMBLE	     , "assemble JIT code")
 DEFTIMEVAR (TV_LINK		     , "link JIT code")
 DEFTIMEVAR (TV_LOAD		     , "load JIT result")
+DEFTIMEVAR (TV_JIT_ACQUIRING_MUTEX   , "acquiring JIT mutex")
+DEFTIMEVAR (TV_JIT_CLIENT_CODE   , "JIT client code")
diff --git a/gcc/timevar.h b/gcc/timevar.h
index 71a814a..85c7610 100644
--- a/gcc/timevar.h
+++ b/gcc/timevar.h
@@ -115,12 +115,24 @@ class timer
   bool cond_start (timevar_id_t tv);
   void cond_stop (timevar_id_t tv);
 
+  void push_client_item (const char *item_name);
+  void pop_client_item ();
+
   void print (FILE *fp);
 
+  const char *get_topmost_item_name () const;
+
  private:
   /* Private member functions.  */
   void validate_phases (FILE *fp) const;
 
+  struct timevar_def;
+  void push_internal (struct timevar_def *tv);
+  void pop_internal ();
+  static void print_row (FILE *fp,
+			 const timevar_time_def *total,
+			 const timevar_def *tv);
+
  private:
 
   /* Private type: a timing variable.  */
@@ -157,6 +169,12 @@ class timer
     struct timevar_stack_def *next;
   };
 
+  /* A class for managing a collection of named timing items, for use
+     e.g. by libgccjit for timing client code.  This class is declared
+     inside timevar.c to avoid everything using timevar.h
+     from needing vec and hash_map.  */
+  class named_items;
+
  private:
 
   /* Data members (all private).  */
@@ -176,6 +194,11 @@ class timer
      pushed.  Time elapsed since then is attributed to the topmost
      element.  */
   timevar_time_def m_start_time;
+
+  /* If non-NULL, for use when timing libgccjit's client code.  */
+  named_items *m_jit_client_items;
+
+  friend class named_items;
 };
 
 /* Provided for backward compatibility.  */
@@ -198,15 +221,18 @@ timevar_pop (timevar_id_t tv)
 class auto_timevar
 {
  public:
-  auto_timevar (timevar_id_t tv)
-    : m_tv (tv)
+  auto_timevar (timer *t, timevar_id_t tv)
+    : m_timer (t),
+      m_tv (tv)
   {
-    timevar_push (m_tv);
+    if (m_timer)
+      m_timer->push (m_tv);
   }
 
   ~auto_timevar ()
   {
-    timevar_pop (m_tv);
+    if (m_timer)
+      m_timer->pop (m_tv);
   }
 
  private:
@@ -214,6 +240,7 @@ class auto_timevar
   // Private to disallow copies.
   auto_timevar (const auto_timevar &);
 
+  timer *m_timer;
   timevar_id_t m_tv;
 };
 
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 1bacb68..0b0c7f1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1781,7 +1781,7 @@ static int rtl_initialized;
 void
 initialize_rtl (void)
 {
-  auto_timevar tv (TV_INITIALIZE_RTL);
+  auto_timevar tv (g_timer, TV_INITIALIZE_RTL);
 
   /* Initialization done just once per compilation, but delayed
      till code generation.  */
@@ -2054,23 +2054,29 @@ do_compile ()
     }
 }
 
-toplev::toplev (bool use_TV_TOTAL, bool init_signals)
-  : m_use_TV_TOTAL (use_TV_TOTAL),
+toplev::toplev (timer *external_timer,
+		bool init_signals)
+  : m_use_TV_TOTAL (external_timer == NULL),
     m_init_signals (init_signals)
 {
-  if (!m_use_TV_TOTAL)
-    start_timevars ();
+  if (external_timer)
+    g_timer = external_timer;
 }
 
 toplev::~toplev ()
 {
-  if (g_timer)
+  if (g_timer && m_use_TV_TOTAL)
     {
       g_timer->stop (TV_TOTAL);
       g_timer->print (stderr);
+      delete g_timer;
+      g_timer = NULL;
     }
 }
 
+/* Potentially call timevar_init (which will create g_timevars if it
+   doesn't already exist).  */
+
 void
 toplev::start_timevars ()
 {
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 3bddcbb..21d9a75 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -24,11 +24,13 @@ along with GCC; see the file COPYING3.  If not see
 extern struct cl_decoded_option *save_decoded_options;
 extern unsigned int save_decoded_options_count;
 
+class timer;
+
 /* Invoking the compiler.  */
 class toplev
 {
 public:
-  toplev (bool use_TV_TOTAL,
+  toplev (timer *external_timer,
 	  bool init_signals);
   ~toplev ();
 
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] gcc parts of timer refactoring
  2015-01-01  0:00 ` [PATCH 1/2] gcc parts of timer refactoring David Malcolm
@ 2015-01-01  0:00   ` Jeff Law
  0 siblings, 0 replies; 4+ messages in thread
From: Jeff Law @ 2015-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm, jit, gcc-patches

On 07/31/2015 03:45 PM, David Malcolm wrote:
> In r223092 (aka dd4d567f4b6b498242097c41d63666bdae320ac1) I moved the
> state of timevar.c from being global data into a "class timer" with
> a global instance "g_timer".
>
> This followup patch generalizes the timing within toplev so that an
> external "timer" instance can (optionally) be passed in; this is used
> in patch 2 to add an API to libgccjit for client code: gcc_jit_timer.
>
> The gcc_jit_timer API allows client code to create arbitrary new timing
> items (beyond the hardcoded list in timevar.def), giving them names,
> so that client code can time whatever things are relevant to it; this
> patch adds the support necessary to timevar.[ch] for this.
>
> The patch also generalizes timevar.h's auto_timevar to avoid it
> depending on the "g_timer" global (which is only set during the
> lifetime of "toplev".  We can use this to add TV_JIT_ACQUIRING_MUTEX,
> and thus measure wallclock time spent waiting for the JIT mutex.
>
> Generalize timevar.c to add support for timing jit client code, by:
>
>   * adding support for timing client items with arbitrary
>     client-supplied names (e.g. "compiling code", "running code" etc).
>
>   * supporting having a "timer" instance created externally and passed
>     in to toplev, allowing clients to control where toplev's timing
>     information is accumulated
>
>   * add a couple of jit-specific timevars
>
> This goes with the next patch; I've split them up for ease of review.
>
> OK for trunk?
>
> gcc/ChangeLog:
> 	* main.c (main): Pass in NULL for toplev's external_timer.
> 	* timevar.c: Include coretypes.h, hash-map.h, vec.h.
> 	(class timer::named_items): New.
> 	(timer::named_items::named_items): New.
> 	(timer::named_items::~named_items): New.
> 	(timer::named_items::push): New.
> 	(timer::named_items::pop): New.
> 	(timer::named_items::print): New.
> 	(timer::timer): Initialize field "m_jit_client_items".
> 	(timer::~timer): New.
> 	(timer::push): Move bulk of implementation to...
> 	(timer::push_internal): ...here.  New function.
> 	(timer::pop): Move bulk of implementation to...
> 	(timer::pop_internal): ...here.  New function.
> 	(timer::push_client_item): New.
> 	(timer::pop_client_item): New.
> 	(timer::print_row): New function, taken from timer::print.
> 	(timer::print): Print "GCC items" header if we also have client
> 	items.  Move row-printing to timer::print_row.  Print any client
> 	items.
> 	(timer::get_topmost_item_name): New method.
> 	* timevar.def (TV_JIT_ACQUIRING_MUTEX): New.
> 	(TV_JIT_CLIENT_CODE): New.
> 	* timevar.h (timer::push_client_item): New declaration.
> 	(timer::pop_client_item): New declaration.
> 	(timer::get_topmost_item_name): New method.
> 	(timer::push_internal): New declaration.
> 	(timer::pop_internal): New declaration.
> 	(timer::print_row): New declaration.
> 	(timer::named_items): New declaration.
> 	(timer::m_jit_client_items): New field.
> 	(timer): Add friend class named_items.
> 	(auto_timevar::auto_timevar): Add timer param.
> 	(auto_timevar::~auto_timevar): Use field "m_timer".
> 	(auto_timevar::m_timer): New field.
> 	* toplev.c (initialize_rtl): Add g_timer as param when
> 	constructing auto_timevar instance.
> 	(toplev::toplev): Add "external_timer" param, and use it to
> 	initialize the "g_timer" global if non-NULL.
> 	(toplev::~toplev): If this created "g_timer", delete it.
> 	* toplev.h (toplev::toplev): Replace "use_TV_TOTAL" bool param
> 	with "external_timer" timer *.
> ---
>   gcc/main.c      |   2 +-
>   gcc/timevar.c   | 247 ++++++++++++++++++++++++++++++++++++++++++++++++--------
>   gcc/timevar.def |   2 +
>   gcc/timevar.h   |  35 +++++++-
>   gcc/toplev.c    |  18 +++--
>   gcc/toplev.h    |   4 +-
>   6 files changed, 261 insertions(+), 47 deletions(-)
>
> diff --git a/gcc/main.c b/gcc/main.c
> index 79baf0d..bbd8b67 100644
> --- a/gcc/main.c
> +++ b/gcc/main.c
> @@ -33,7 +33,7 @@ int main (int argc, char **argv);
>   int
>   main (int argc, char **argv)
>   {
> -  toplev toplev (true, /* use_TV_TOTAL */
> +  toplev toplev (NULL, /* external_timer */
>   		 true /* init_signals */);
>
>     return toplev.main (argc, argv);
> diff --git a/gcc/timevar.c b/gcc/timevar.c
> index 76ad22a..eebb1dc 100644
> --- a/gcc/timevar.c
> +++ b/gcc/timevar.c
> @@ -20,7 +20,10 @@ along with GCC; see the file COPYING3.  If not see
>
>   #include "config.h"
>   #include "system.h"
> +#include "coretypes.h"
>   #include "timevar.h"
> +#include "hash-map.h"
> +#include "vec.h"
You shouldn't need to include hash-map.h and vec.h, as those get pulled 
in via core-types.h including hash-table.h now.

> +  for (iter = m_stack; iter; iter=next)
Nit, whitespace around the '=' in iter=next assignment.

> +    {
> +      next = iter->next;
> +      free (iter);
> +    }
> +  for (iter = m_unused_stack_instances; iter; iter=next)
Here too.

OK with those nits fixed.

jeff

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/2] jit: add timing API
  2015-01-01  0:00 [PATCH 0/2] Refactoring of timevar API David Malcolm
  2015-01-01  0:00 ` [PATCH 1/2] gcc parts of timer refactoring David Malcolm
@ 2015-01-01  0:00 ` David Malcolm
  1 sibling, 0 replies; 4+ messages in thread
From: David Malcolm @ 2015-01-01  0:00 UTC (permalink / raw)
  To: jit, gcc-patches; +Cc: David Malcolm

This requires and is required by the previous patch; I've split
them up to make the earlier patch easier to review.

gcc/jit/ChangeLog:
	* docs/topics/compatibility.rst (LIBGCCJIT_ABI_4): New.
	* docs/topics/contexts.rst (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY):
	We no longer show a profile.
	* docs/topics/index.rst (Topic Reference): Add performance.rst.
	* docs/topics/performance.rst: New file.
	* jit-playback.c (gcc::jit::playback::context::compile): Add timer
	param when constructing the "toplev" instance.
	(gcc::jit::playback::context::acquire_mutex): Add timer param when
	constructing auto_timevar instance.
	(gcc::jit::playback::context::make_fake_args): If we have a timer,
	add "-ftime-report".
	(gcc::jit::playback::context::invoke_driver): Add timer param when
	constructing auto_timevar instance.
	(gcc::jit::playback::context::dlopen_built_dso): Likewise.
	* jit-playback.h (gcc::jit::playback::context::get_timer): New accessor.
	* jit-recording.c: Include timevar.h.
	(gcc::jit::recording::context::context): Initialize field "m_timer".
	* jit-recording.h: Add forward declaration of class timer.
	(gcc::jit::recording::context::set_timer): New method.
	(gcc::jit::recording::context::get_timer): New method.
	(gcc::jit::recording::context::m_timer): New field.
	* libgccjit++.h (gccjit::timer): New class.
	(gccjit::auto_time): New class.
	(gccjit::context::set_timer): New method.
	(gccjit::context::get_timer): New.
	(gccjit::timer::timer): New.
	(gccjit::timer::push): New.
	(gccjit::timer::pop): New.
	(timer::print): New.
	(timer::get_inner_timer): New.
	(timer::release): New.
	(auto_time::auto_time): New.
	(auto_time::~auto_time): New.
	* libgccjit.c: Include timevar.h.
	(struct gcc_jit_timer): New.
	(gcc_jit_timer_new): New function.
	(gcc_jit_timer_release): New function.
	(gcc_jit_context_set_timer): New function.
	(gcc_jit_context_get_timer): New function.
	(gcc_jit_timer_push): New function.
	(gcc_jit_timer_pop): New function.
	(gcc_jit_timer_print): New function.
	* libgccjit.h (LIBGCCJIT_HAVE_TIMING_API): New macro.
	(gcc_jit_timer): New typedef.
	(gcc_jit_timer_new): New function.
	(gcc_jit_timer_release): New function.
	(gcc_jit_context_set_timer): New function.
	(gcc_jit_context_get_timer): New function.
	(gcc_jit_timer_push): New function.
	(gcc_jit_timer_pop): New function.
	(gcc_jit_timer_print): New function.
	* libgccjit.map (LIBGCCJIT_ABI_4): New.
	(gcc_jit_timer_new): New function.
	(gcc_jit_timer_release): New function.
	(gcc_jit_context_set_timer): New function.
	(gcc_jit_context_get_timer): New function.
	(gcc_jit_timer_push): New function.
	(gcc_jit_timer_pop): New function.
	(gcc_jit_timer_print): New function.

gcc/testsuite/ChangeLog:
	* jit.dg/test-benchmark.c (test_jit): Add param "timer" and use
	it to push/pop timing items.
	(main): For each optimization level, create a gcc_jit_timer, and
	time all of the iteration within that level cumulatively.
	* jit.dg/test-error-gcc_jit_timer_pop-mismatch.c: New test case.
	* jit.dg/test-error-gcc_jit_timer_pop-too-many.c: New test case.
---
 gcc/jit/docs/topics/compatibility.rst              |  21 ++
 gcc/jit/docs/topics/contexts.rst                   |   3 +-
 gcc/jit/docs/topics/index.rst                      |   1 +
 gcc/jit/docs/topics/performance.rst                | 240 +++++++++++++++++++++
 gcc/jit/jit-playback.c                             |  11 +-
 gcc/jit/jit-playback.h                             |   2 +
 gcc/jit/jit-recording.c                            |   2 +
 gcc/jit/jit-recording.h                            |   7 +
 gcc/jit/libgccjit++.h                              | 117 ++++++++++
 gcc/jit/libgccjit.c                                | 109 ++++++++++
 gcc/jit/libgccjit.h                                |  84 ++++++++
 gcc/jit/libgccjit.map                              |  12 ++
 gcc/testsuite/jit.dg/test-benchmark.c              |  20 +-
 .../jit.dg/test-error-gcc_jit_timer_pop-mismatch.c |  22 ++
 .../jit.dg/test-error-gcc_jit_timer_pop-too-many.c |  21 ++
 15 files changed, 665 insertions(+), 7 deletions(-)
 create mode 100644 gcc/jit/docs/topics/performance.rst
 create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-mismatch.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-too-many.c

diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 37e2866..0a4b453 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -107,3 +107,24 @@ entrypoints:
   * :func:`gcc_jit_case_as_object`
 
   * :func:`gcc_jit_context_new_case`
+
+.. _LIBGCCJIT_ABI_4:
+
+``LIBGCCJIT_ABI_4``
+-------------------
+``LIBGCCJIT_ABI_4`` covers the addition of timers via API
+entrypoints:
+
+  * :func:`gcc_jit_context_get_timer`
+
+  * :func:`gcc_jit_context_set_timer`
+
+  * :func:`gcc_jit_timer_new`
+
+  * :func:`gcc_jit_timer_release`
+
+  * :func:`gcc_jit_timer_push`
+
+  * :func:`gcc_jit_timer_pop`
+
+  * :func:`gcc_jit_timer_print`
diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index 78bcb71..1aa319a 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -430,8 +430,7 @@ Boolean options
   .. macro:: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
 
      If true, :func:`gcc_jit_context_compile` will print information to stderr
-     on the actions it is performing, followed by a profile showing
-     the time taken and memory usage of each phase.
+     on the actions it is performing.
 
   .. macro:: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
 
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
index 76b3d0b..d32f63b 100644
--- a/gcc/jit/docs/topics/index.rst
+++ b/gcc/jit/docs/topics/index.rst
@@ -29,3 +29,4 @@ Topic Reference
    locations.rst
    compilation.rst
    compatibility.rst
+   performance.rst
diff --git a/gcc/jit/docs/topics/performance.rst b/gcc/jit/docs/topics/performance.rst
new file mode 100644
index 0000000..4dfc139
--- /dev/null
+++ b/gcc/jit/docs/topics/performance.rst
@@ -0,0 +1,240 @@
+.. Copyright (C) 2015 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Performance
+===========
+
+The timing API
+--------------
+
+As of GCC 6, libgccjit exposes a timing API, for printing reports on
+how long was spent in different parts of code.
+
+You can create a :c:type:`gcc_jit_timer` instance, which will
+measure time spent since its creation.  The timer maintains a stack
+of "timer items": as control flow moves through your code, you can push
+and pop named items relating to your code onto the stack, and the timer
+will account the time spent accordingly.
+
+You can also asssociate a timer with a :c:type:`gcc_jit_context`, in
+which case the time spent inside compilation will be subdivided.
+
+For example, the following code uses a timer, recording client items
+"create_code", "compile", and "running code":
+
+.. code-block:: c
+
+  /* Create a timer.  */
+  gcc_jit_timer *timer = gcc_jit_timer_new ();
+  if (!timer)
+    {
+       error ("gcc_jit_timer_new failed");
+       return -1;
+    }
+
+  /* Let's repeatedly compile and run some code, accumulating it
+     all into the timer.  */
+  for (int i = 0; i < num_iterations; i++)
+    {
+      /* Create a context and associate it with the timer.  */
+      gcc_jit_context *ctxt = gcc_jit_context_acquire ();
+      if (!ctxt)
+        {
+          error ("gcc_jit_context_acquire failed");
+          return -1;
+        }
+      gcc_jit_context_set_timer (ctxt, timer);
+
+      /* Populate the context, timing it as client item "create_code".  */
+      gcc_jit_timer_push (timer, "create_code");
+      create_code (ctxt);
+      gcc_jit_timer_pop (timer, "create_code");
+
+      /* Compile the context, timing it as client item "compile".  */
+      gcc_jit_timer_push (timer, "compile");
+      result = gcc_jit_context_compile (ctxt);
+      gcc_jit_timer_pop (timer, "compile");
+
+      /* Run the generated code, timing it as client item "running code".  */
+      gcc_jit_timer_push (timer, "running code");
+      run_the_code (ctxt, result);
+      gcc_jit_timer_pop (timer, "running code");
+
+      /* Clean up.  */
+      gcc_jit_context_release (ctxt);
+      gcc_jit_result_release (result);
+  }
+
+  /* Print the accumulated timings.  */
+  gcc_jit_timer_print (timer, stderr);
+  gcc_jit_timer_release (timer);
+
+giving output like this, showing the internal GCC items at the top, then
+client items, then the total::
+
+  Execution times (seconds)
+  GCC items:
+   phase setup             :   0.29 (14%) usr   0.00 ( 0%) sys   0.32 ( 5%) wall   10661 kB (50%) ggc
+   phase parsing           :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     653 kB ( 3%) ggc
+   phase finalize          :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   dump files              :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall       0 kB ( 0%) ggc
+   callgraph construction  :   0.02 ( 1%) usr   0.01 ( 6%) sys   0.01 ( 0%) wall     242 kB ( 1%) ggc
+   callgraph optimization  :   0.03 ( 2%) usr   0.00 ( 0%) sys   0.02 ( 0%) wall     142 kB ( 1%) ggc
+   trivially dead code     :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   df scan insns           :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       9 kB ( 0%) ggc
+   df live regs            :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall       0 kB ( 0%) ggc
+   inline parameters       :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall      82 kB ( 0%) ggc
+   tree CFG cleanup        :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   tree PHI insertion      :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.02 ( 0%) wall      64 kB ( 0%) ggc
+   tree SSA other          :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall      18 kB ( 0%) ggc
+   expand                  :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     398 kB ( 2%) ggc
+   jump                    :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   loop init               :   0.01 ( 0%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall      67 kB ( 0%) ggc
+   integrated RA           :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall    2468 kB (12%) ggc
+   thread pro- & epilogue  :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     162 kB ( 1%) ggc
+   final                   :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     216 kB ( 1%) ggc
+   rest of compilation     :   1.37 (69%) usr   0.00 ( 0%) sys   1.13 (18%) wall    1391 kB ( 6%) ggc
+   assemble JIT code       :   0.01 ( 1%) usr   0.00 ( 0%) sys   4.04 (66%) wall       0 kB ( 0%) ggc
+   load JIT result         :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   JIT client code         :   0.00 ( 0%) usr   0.01 ( 6%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+  Client items:
+   create_code             :   0.00 ( 0%) usr   0.01 ( 6%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   compile                 :   0.36 (18%) usr   0.15 (83%) sys   0.86 (14%) wall   14939 kB (70%) ggc
+   running code            :   0.00 ( 0%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   TOTAL                   :   2.00             0.18             6.12              21444 kB
+
+The exact format is intended to be human-readable, and is subject to change.
+
+.. macro:: LIBGCCJIT_HAVE_TIMING_API
+
+   The timer API was added to libgccjit in GCC 6.
+   This macro is only defined in versions of libgccjit.h which have the
+   timer API, and so can be used to guard code that may need to compile
+   against earlier releases::
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+     gcc_jit_timer *t = gcc_jit_timer_new ();
+     gcc_jit_context_set_timer (ctxt, t);
+     #endif
+
+.. type:: gcc_jit_timer
+
+.. function:: gcc_jit_timer * gcc_jit_timer_new(void)
+
+   Create a :c:type:`gcc_jit_timer` instance, and start timing::
+
+     gcc_jit_timer *t = gcc_jit_timer_new ();
+
+   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+
+.. function:: void gcc_jit_timer_release(gcc_jit_timer *timer)
+
+   Release a :c:type:`gcc_jit_timer` instance::
+
+     gcc_jit_timer_release (t);
+
+   This should be called exactly once on a timer.
+
+   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+
+.. function:: void gcc_jit_context_set_timer(gcc_jit_context *ctxt, \
+                                             gcc_jit_timer *timer)
+
+   Associate a :c:type:`gcc_jit_timer` instance with a context::
+
+      gcc_jit_context_set_timer (ctxt, t);
+
+   A timer instance can be shared between multiple
+   :c:type:`gcc_jit_context` instances.
+
+   Timers have no locking, so if you have a multithreaded program, you
+   must provide your own locks if more than one thread could be working
+   with the same timer via timer-associated contexts.
+
+   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+
+.. function:: gcc_jit_timer *gcc_jit_context_get_timer(gcc_jit_context *ctxt)
+
+   Get the timer associated with a context (if any).
+
+   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+
+.. function:: void gcc_jit_timer_push(gcc_jit_timer *timer, \
+                                      const char *item_name)
+
+   Push the given item onto the timer's stack::
+
+      gcc_jit_timer_push (t, "running code");
+      run_the_code (ctxt, result);
+      gcc_jit_timer_pop (t, "running code");
+
+   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+
+.. function:: void gcc_jit_timer_pop(gcc_jit_timer *timer, \
+                                     const char *item_name)
+
+   Pop the top item from the timer's stack.
+
+   If "item_name" is provided, it must match that of the top item.
+   Alternatively, ``NULL`` can be passed in, to suppress checking.
+
+   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+
+.. function:: void gcc_jit_timer_print(gcc_jit_timer *timer, \
+                                       FILE *f_out)
+
+   Print timing information to the given stream about activity since
+   the timer was started.
+
+   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
+   for its presence using
+
+   .. code-block:: c
+
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index c469863..925fa86 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1793,7 +1793,7 @@ compile ()
     }
 
   /* This runs the compiler.  */
-  toplev toplev (false, /* use_TV_TOTAL */
+  toplev toplev (get_timer (), /* external_timer */
 		 false); /* init_signals */
   enter_scope ("toplev::main");
   if (get_logger ())
@@ -2085,6 +2085,8 @@ static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
 void
 playback::context::acquire_mutex ()
 {
+  auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
+
   /* Acquire the big GCC mutex. */
   JIT_LOG_SCOPE (get_logger ());
   pthread_mutex_lock (&jit_mutex);
@@ -2252,6 +2254,9 @@ make_fake_args (vec <char *> *argvec,
       }
   }
 
+  if (get_timer ())
+    ADD_ARG ("-ftime-report");
+
   /* Add any user-provided extra options, starting with any from
      parent contexts.  */
   m_recording_ctxt->append_command_line_options (argvec);
@@ -2380,7 +2385,7 @@ invoke_driver (const char *ctxt_progname,
   JIT_LOG_SCOPE (get_logger ());
   /* Currently this lumps together both assembling and linking into
      TV_ASSEMBLE.  */
-  auto_timevar assemble_timevar (tv_id);
+  auto_timevar assemble_timevar (get_timer (), tv_id);
   const char *errmsg;
   auto_argvec argvec;
 #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
@@ -2492,7 +2497,7 @@ playback::context::
 dlopen_built_dso ()
 {
   JIT_LOG_SCOPE (get_logger ());
-  auto_timevar load_timevar (TV_LOAD);
+  auto_timevar load_timevar (get_timer (), TV_LOAD);
   void *handle = NULL;
   const char *error = NULL;
   result *result_obj = NULL;
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 1d7de17..52e402f 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -215,6 +215,8 @@ public:
     return m_recording_ctxt->errors_occurred ();
   }
 
+  timer *get_timer () const { return m_recording_ctxt->get_timer (); }
+
 private:
   void dump_generated_code ();
 
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index d888b0e..811d7c0 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "pretty-print.h"
 #include "hash-map.h"
 #include "toplev.h"
+#include "timevar.h"
 
 #include <pthread.h>
 
@@ -461,6 +462,7 @@ recording::context::context (context *parent_ctxt)
   : log_user (NULL),
     m_parent_ctxt (parent_ctxt),
     m_toplevel_ctxt (m_parent_ctxt ? m_parent_ctxt->m_toplevel_ctxt : this),
+    m_timer (NULL),
     m_error_count (0),
     m_first_error_str (NULL),
     m_owns_first_error_str (false),
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 884304b..3d88b89 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "jit-common.h"
 #include "jit-logging.h"
 
+class timer;
+
 namespace gcc {
 
 namespace jit {
@@ -276,6 +278,9 @@ public:
   void
   get_all_requested_dumps (vec <recording::requested_dump> *out);
 
+  void set_timer (timer *t) { m_timer = t; }
+  timer *get_timer () const { return m_timer; }
+
 private:
   void log_all_options () const;
   void log_str_option (enum gcc_jit_str_option opt) const;
@@ -292,6 +297,8 @@ private:
      contexts.  This has itself as its own m_toplevel_ctxt.  */
   context *m_toplevel_ctxt;
 
+  timer *m_timer;
+
   int m_error_count;
 
   char *m_first_error_str;
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 01579bd..d7e491b 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -46,6 +46,8 @@ namespace gccjit
      class lvalue;
        class param;
     class case_;
+  class timer;
+  class auto_time;
 
   /* Errors within the API become C++ exceptions of this class.  */
   class error
@@ -125,6 +127,9 @@ namespace gccjit
 
     void add_command_line_option (const char *optname);
 
+    void set_timer (gccjit::timer t);
+    gccjit::timer get_timer () const;
+
     location
     new_location (const std::string &filename,
 		  int line,
@@ -523,6 +528,36 @@ namespace gccjit
 
   /* Dereferencing. */
   lvalue operator* (rvalue ptr);
+
+  class timer
+  {
+  public:
+    timer ();
+    timer (gcc_jit_timer *inner_timer);
+
+    void push (const char *item_name);
+    void pop (const char *item_name);
+    void print (FILE *f_out) const;
+
+    void release ();
+
+    gcc_jit_timer *get_inner_timer () const;
+
+  private:
+    gcc_jit_timer *m_inner_timer;
+  };
+
+  class auto_time
+  {
+  public:
+    auto_time (timer t, const char *item_name);
+    auto_time (context ctxt, const char *item_name);
+    ~auto_time ();
+
+  private:
+    timer m_timer;
+    const char *m_item_name;
+  };
 }
 
 /****************************************************************************
@@ -636,6 +671,19 @@ context::add_command_line_option (const char *optname)
   gcc_jit_context_add_command_line_option (m_inner_ctxt, optname);
 }
 
+inline void
+context::set_timer (gccjit::timer t)
+{
+  gcc_jit_context_set_timer (m_inner_ctxt, t.get_inner_timer ());
+}
+
+inline gccjit::timer
+context::get_timer () const
+{
+  return gccjit::timer (gcc_jit_context_get_timer (m_inner_ctxt));
+}
+
+
 inline location
 context::new_location (const std::string &filename,
 		       int line,
@@ -1713,6 +1761,75 @@ inline lvalue operator* (rvalue ptr)
   return ptr.dereference ();
 }
 
+// class timer
+inline
+timer::timer ()
+{
+  m_inner_timer = gcc_jit_timer_new ();
+}
+
+inline
+timer::timer (gcc_jit_timer *inner_timer)
+{
+  m_inner_timer = inner_timer;
+}
+
+inline void
+timer::push (const char *item_name)
+{
+  gcc_jit_timer_push (m_inner_timer, item_name);
+
+}
+
+inline void
+timer::pop (const char *item_name)
+{
+  gcc_jit_timer_pop (m_inner_timer, item_name);
+}
+
+inline void
+timer::print (FILE *f_out) const
+{
+  gcc_jit_timer_print (m_inner_timer, f_out);
+}
+
+inline gcc_jit_timer *
+timer::get_inner_timer () const
+{
+  return m_inner_timer;
+}
+
+inline void
+timer::release ()
+{
+  gcc_jit_timer_release (m_inner_timer);
+  m_inner_timer = NULL;
+}
+
+// class auto_time
+
+inline
+auto_time::auto_time (timer t, const char *item_name)
+  : m_timer (t),
+    m_item_name (item_name)
+{
+  t.push (item_name);
+}
+
+inline
+auto_time::auto_time (context ctxt, const char *item_name)
+  : m_timer (ctxt.get_timer ()),
+    m_item_name (item_name)
+{
+  m_timer.push (item_name);
+}
+
+inline
+auto_time::~auto_time ()
+{
+  m_timer.pop (m_item_name);
+}
+
 } // namespace gccjit
 
 #endif /* #ifndef LIBGCCJIT_PLUS_PLUS_H */
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index eee513f..eb9200c 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "opts.h"
 #include "safe-ctype.h"
 #include "typed-splay-tree.h"
+#include "timevar.h"
 
 #include "libgccjit.h"
 #include "jit-common.h"
@@ -89,6 +90,10 @@ struct gcc_jit_case : public gcc::jit::recording::case_
 {
 };
 
+struct gcc_jit_timer : public timer
+{
+};
+
 /**********************************************************************
  Error-handling.
 
@@ -2828,3 +2833,107 @@ gcc_jit_result_release (gcc_jit_result *result)
   result->log ("deleting result: %p", (void *)result);
   delete result;
 }
+
+/**********************************************************************
+ Timing support.
+ **********************************************************************/
+
+/* Create a gcc_jit_timer instance, and start timing.  */
+
+gcc_jit_timer *
+gcc_jit_timer_new (void)
+{
+  gcc_jit_timer *timer = new gcc_jit_timer ();
+  timer->start (TV_TOTAL);
+  timer->push (TV_JIT_CLIENT_CODE);
+  return timer;
+}
+
+/* Release a gcc_jit_timer instance.  */
+
+void
+gcc_jit_timer_release (gcc_jit_timer *timer)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+
+  delete timer;
+}
+
+/* Associate a gcc_jit_timer instance with a context.  */
+
+void
+gcc_jit_context_set_timer (gcc_jit_context *ctxt,
+			   gcc_jit_timer *timer)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL ctxt");
+  RETURN_IF_FAIL (timer, ctxt, NULL, "NULL timer");
+
+  ctxt->set_timer (timer);
+}
+
+/* Get the timer associated with a context (if any).  */
+
+gcc_jit_timer *
+gcc_jit_context_get_timer (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL ctxt");
+
+  return (gcc_jit_timer *)ctxt->get_timer ();
+}
+
+/* Push the given item onto the timing stack.  */
+
+void
+gcc_jit_timer_push (gcc_jit_timer *timer,
+		    const char *item_name)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+  RETURN_IF_FAIL (item_name, NULL, NULL, "NULL item_name");
+  timer->push_client_item (item_name);
+}
+
+/* Pop the top item from the timing stack.  */
+
+void
+gcc_jit_timer_pop (gcc_jit_timer *timer,
+		   const char *item_name)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+
+  if (item_name)
+    {
+      const char *top_item_name = timer->get_topmost_item_name ();
+
+      RETURN_IF_FAIL_PRINTF1
+	(top_item_name, NULL, NULL,
+	 "pop of empty timing stack (attempting to pop: \"%s\")",
+	 item_name);
+
+      RETURN_IF_FAIL_PRINTF2
+	(0 == strcmp (item_name, top_item_name), NULL, NULL,
+	 "mismatching item_name:"
+	 " top of timing stack: \"%s\","
+	 " attempting to pop: \"%s\"",
+	 top_item_name,
+	 item_name);
+    }
+
+  timer->pop_client_item ();
+}
+
+/* Print timing information to the given stream about activity since
+   the timer was started.  */
+
+void
+gcc_jit_timer_print (gcc_jit_timer *timer,
+		     FILE *f_out)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+  RETURN_IF_FAIL (f_out, NULL, NULL, "NULL f_out");
+
+  timer->pop (TV_JIT_CLIENT_CODE);
+  timer->stop (TV_TOTAL);
+  timer->print (f_out);
+  timer->start (TV_TOTAL);
+  timer->push (TV_JIT_CLIENT_CODE);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 32f2a5d..88e4ff3 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1266,6 +1266,90 @@ gcc_jit_context_enable_dump (gcc_jit_context *ctxt,
 			     const char *dumpname,
 			     char **out_ptr);
 
+/**********************************************************************
+ Timing support.
+ **********************************************************************/
+
+/* The timing API was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+#define LIBGCCJIT_HAVE_TIMING_API
+
+typedef struct gcc_jit_timer gcc_jit_timer;
+
+/* Create a gcc_jit_timer instance, and start timing.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+extern gcc_jit_timer *
+gcc_jit_timer_new (void);
+
+/* Release a gcc_jit_timer instance.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+extern void
+gcc_jit_timer_release (gcc_jit_timer *timer);
+
+/* Associate a gcc_jit_timer instance with a context.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+extern void
+gcc_jit_context_set_timer (gcc_jit_context *ctxt,
+			   gcc_jit_timer *timer);
+
+/* Get the timer associated with a context (if any).
+
+   This API entrypoint was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+
+extern gcc_jit_timer *
+gcc_jit_context_get_timer (gcc_jit_context *ctxt);
+
+/* Push the given item onto the timing stack.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+
+extern void
+gcc_jit_timer_push (gcc_jit_timer *timer,
+		    const char *item_name);
+
+/* Pop the top item from the timing stack.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+
+extern void
+gcc_jit_timer_pop (gcc_jit_timer *timer,
+		   const char *item_name);
+
+/* Print timing information to the given stream about activity since
+   the timer was started.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_4; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TIMING_API
+*/
+
+extern void
+gcc_jit_timer_print (gcc_jit_timer *timer,
+		     FILE *f_out);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 3c0a0c1..e4302c6 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -128,3 +128,15 @@ LIBGCCJIT_ABI_3 {
     gcc_jit_case_as_object;
     gcc_jit_context_new_case;
 } LIBGCCJIT_ABI_2;
+
+# Add timing API.
+LIBGCCJIT_ABI_4 {
+  global:
+    gcc_jit_context_get_timer;
+    gcc_jit_context_set_timer;
+    gcc_jit_timer_new;
+    gcc_jit_timer_release;
+    gcc_jit_timer_push;
+    gcc_jit_timer_pop;
+    gcc_jit_timer_print;
+};
diff --git a/gcc/testsuite/jit.dg/test-benchmark.c b/gcc/testsuite/jit.dg/test-benchmark.c
index 324ba93..4952fff 100644
--- a/gcc/testsuite/jit.dg/test-benchmark.c
+++ b/gcc/testsuite/jit.dg/test-benchmark.c
@@ -141,11 +141,13 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
 
 /* Run one iteration of the test.  */
 static void
-test_jit (const char *argv0, int opt_level)
+test_jit (const char *argv0, int opt_level, gcc_jit_timer *timer)
 {
   gcc_jit_context *ctxt;
   gcc_jit_result *result;
 
+  gcc_jit_timer_push (timer, "test_jit");
+
   ctxt = gcc_jit_context_acquire ();
   if (!ctxt)
     {
@@ -153,6 +155,8 @@ test_jit (const char *argv0, int opt_level)
       return;
     }
 
+  gcc_jit_context_set_timer (ctxt, timer);
+
   /* Set up options.  */
   gcc_jit_context_set_str_option (
     ctxt,
@@ -182,13 +186,22 @@ test_jit (const char *argv0, int opt_level)
       GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
       1);
 
+  gcc_jit_timer_push (timer, "create_code");
   create_code (ctxt, NULL);
+  gcc_jit_timer_pop (timer, "create_code");
 
+  gcc_jit_timer_push (timer, "compile");
   result = gcc_jit_context_compile (ctxt);
+  gcc_jit_timer_pop (timer, "compile");
+
+  gcc_jit_timer_push (timer, "verify_code");
   verify_code (ctxt, result);
+  gcc_jit_timer_pop (timer, "verify_code");
 
   gcc_jit_context_release (ctxt);
   gcc_jit_result_release (result);
+
+  gcc_jit_timer_pop (timer, "test_jit");
 }
 
 /* Taken from timevar.c.  */
@@ -217,16 +230,19 @@ main (int argc, char **argv)
       int i;
       double start_time, end_time, elapsed_time;
       start_time = get_wallclock_time ();
+      gcc_jit_timer *timer = gcc_jit_timer_new ();
       for (i = 1; i <= num_iterations; i++)
 	{
 	  snprintf (test, sizeof (test),
 		    "%s iteration %d of %d",
 		    extract_progname (argv[0]),
 		    i, num_iterations);
-	  test_jit (argv[0], opt_level);
+	  test_jit (argv[0], opt_level, timer);
 	}
       end_time = get_wallclock_time ();
       elapsed_time = end_time - start_time;
+      gcc_jit_timer_print (timer, stderr);
+      gcc_jit_timer_release (timer);
       pass ("%s: survived %i iterations at optlevel %i",
 	    argv[0], num_iterations, opt_level);
       note (("%s: %i iterations at optlevel %i"
diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-mismatch.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-mismatch.c
new file mode 100644
index 0000000..d0862dd
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-mismatch.c
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_timer *timer = gcc_jit_timer_new ();
+  /* Error: mismatched push/pop.  */
+  gcc_jit_timer_push (timer, "apples");
+  gcc_jit_timer_pop (timer, "oranges");
+  gcc_jit_timer_release (timer);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* empty */
+}
diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-too-many.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-too-many.c
new file mode 100644
index 0000000..62faeaf
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_timer_pop-too-many.c
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_timer *timer = gcc_jit_timer_new ();
+  /* Erroneous: pop of an empty timing stack.  */
+  gcc_jit_timer_pop (timer, "test");
+  gcc_jit_timer_release (timer);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* empty */
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-08-03 17:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-01  0:00 [PATCH 0/2] Refactoring of timevar API David Malcolm
2015-01-01  0:00 ` [PATCH 1/2] gcc parts of timer refactoring David Malcolm
2015-01-01  0:00   ` Jeff Law
2015-01-01  0:00 ` [PATCH 2/2] jit: add timing API David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).